package com.xlf.service.base.service.importProblem.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xlf.common.core.exception.BizException;
import com.xlf.common.core.util.StringUtils;
import com.xlf.common.core.util.file.UploadConfig;
import com.xlf.pojo.base.*;
import com.xlf.pojo.constant.Constants;
import com.xlf.service.base.mapper.*;
import com.xlf.service.base.pojo.vo.ImportProblemVO;
import com.xlf.service.base.service.ProblemCaseService;
import com.xlf.service.base.service.ProblemService;
import com.xlf.service.base.service.importProblem.impl.ProblemCaseImportService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author xlf 2734029211@qq.com
 * @Date 2023/11/29 16:17
 * @Description: TODO 解析标准的json文件生成problem,测试用例读取后导入到数据库中
 * @Version 1.0
 */
@Service
public class ProblemImportService extends ProblemCaseImportService {


    @Resource
    protected TagMapper tagMapper;

    @Resource
    protected LanguageMapper languageMapper;

    @Autowired
    protected ProblemService problemService;

    /**
     *
     * @param workFileDir 文件所在的工作目录
     */
    @Transactional
    public void importProblem(String workFileDir){

        File testCaseFileList = new File(workFileDir);
        //获取文件列表
        File[] files = testCaseFileList.listFiles();

        //获取JSON题目文件
        HashMap<String, File> problemInfo = getJSONFile(files);

        //读取json文件生成对象
        HashMap<String, ImportProblemVO> problemVoMap = getImportProblemVOHashMap(problemInfo);

        //获取文件夹
        HashMap<String, File> testcaseInfo = getTestcaseFile(files);

        //获取系统语言
        Map<String, Language> languageMap = getLanguageMap();

        //获取系统标签
        Map<String, Long> tagMap = getTagMap();

        List<Problem> problems = new ArrayList<>();
        for (String key : problemInfo.keySet()){

            if("default".equals(key) || "cover".equals(key))
                continue;

            ImportProblemVO importProblemVo = problemVoMap.get(key);

            Problem problem = getProblem(languageMap, tagMap, importProblemVo,key);

            //格式化用例
            File testFile = testcaseInfo.getOrDefault(key, null);
            if (testFile == null) {
                throw new BizException("请检查编号为：" + key + "的题目数据文件与测试数据文件夹是否一一对应！");
            }

            ArrayList<ProblemCase> problemCases = getProblemCases(testFile);
            problem.setProblemCase(problemCases);
            problems.add(problem);

        }

        //默认模板
        Problem defaultProblem = getProblem(languageMap, tagMap,problemVoMap, "default");

        //覆盖模板
        Problem coverProblem = getProblem(languageMap, tagMap,problemVoMap, "cover");

        problems.forEach(item -> {
            //设置默认和覆盖
            importProblemBeforeHandle(defaultProblem, coverProblem, item);
            problemService.saveOrUpdate_(item);
        });
    }

    @Transactional
    public void importProblem(MultipartFile file) {
        //获取工作目录
        String fileDir = initWorkFileDir(file);
        importProblem(fileDir);

    }

    protected void importProblemBeforeHandle(Problem defaultProblem, Problem coverProblem, Problem problem) {
        if(defaultProblem != null)
            setDefaultProblem(problem, defaultProblem);
        if(coverProblem != null)
            setCoverProblem(problem, coverProblem);
    }

    protected Problem getProblem(Map<String, Language> languageMap, Map<String, Long> tagMap,HashMap<String, ImportProblemVO> problemVoMap, String key) {
        Problem defaultProblem = null;
        ImportProblemVO aDefault = problemVoMap.get(key);
        if (aDefault != null) {
            defaultProblem = getProblem(languageMap, tagMap,aDefault,key);
        }
        return defaultProblem;
    }

    protected Problem getProblem(Map<String, Language> languageMap, Map<String, Long> tagMap, ImportProblemVO importProblemVo,String key) {

        // 格式化标签
        List<Long> tags = new ArrayList<>();
        for (String tagStr : importProblemVo.getTags()) {
            Long tagId = tagMap.getOrDefault(tagStr.toUpperCase(), null);
            if (tagId == null) {
                throw new BizException("请检查编号为：" + key + "的题目的标签是否有错，不要添加没有的标签！");
            } else {
                tags.add(tagId);
            }
        }

        // 格式化题目语言
        Map<String, String> codeTemplateMap = importProblemVo.getCodeTemplates().stream()
                .collect(Collectors.toMap(item -> item.get("language"), item -> item.get("code")));
        List<ProblemLanguage> languages = new ArrayList<>();
        for (String lang : importProblemVo.getLanguages()) {
            Language language = languageMap.getOrDefault(lang, null);
            if (language == null) {
                throw new BizException("请检查编号为：" + key + "的题目的代码语言是否有错，不要添加不支持的语言！");
            }
            String code = codeTemplateMap.get(lang) != null ? codeTemplateMap.get(lang) : language.getCodeTemplate();
            languages.add(new ProblemLanguage()
                    .setLid(language.getId())
                    .setCode(code)
                    .setName(lang));
        }
        Problem problem = BeanUtil.fillBeanWithMap(importProblemVo.getProblem(), new Problem(), true);
        problem.setTagIds(tags);
        problem.setProblemLanguageList(languages);

        return problem;
    }

    protected Problem getProblem(Map<String, Language> languageMap, Map<String, Long> tagMap, ImportProblemVO importProblemVo) {

        return getProblem(languageMap,tagMap,importProblemVo,"-");
    }

    /**
     * 文件必须是标准格式导入的json文件
     * @param problemInfo 文件 {key:文件名，value:文件}
     * @return 标准文件生成的java对象
     */
    protected HashMap<String, ImportProblemVO> getImportProblemVOHashMap(HashMap<String, File> problemInfo) {
        HashMap<String, ImportProblemVO> problemVoMap = new HashMap<>();
        for (String key : problemInfo.keySet()) {
            try {
                ImportProblemVO importProblemVO = parseProblemVO(problemInfo.get(key));
                problemVoMap.put(key, importProblemVO);
            } catch (Exception e) {
                throw new BizException("请检查编号为：" + key + "的题目json文件的格式：" + e.getLocalizedMessage());
            }
        }
        return problemVoMap;
    }

    /**
     * 文件必须是标准格式导入的json文件
     * @param problemInfo 文件 {key:文件名，value:文件}
     * @param fileNames 文件名过滤
     * @return 标准文件生成的java对象
     */
    protected HashMap<String, ImportProblemVO> getImportProblemVOHashMap(HashMap<String, File> problemInfo,List<String> fileNames) {
        HashMap<String, ImportProblemVO> problemVoMap = new HashMap<>();
        for (String key : problemInfo.keySet()) {
            if(!fileNames.contains(key))
                continue;
            try {
                ImportProblemVO importProblemVO = parseProblemVO(problemInfo.get(key));
                problemVoMap.put(key, importProblemVO);
            } catch (Exception e) {
                throw new BizException("请检查编号为：" + key + "的题目json文件的格式：" + e.getLocalizedMessage());
            }
        }
        return problemVoMap;
    }


    /**
     *
     * @return 系统标签
     */
    protected Map<String, Long> getTagMap() {
        //标签
        Map<String, Long> tagMap = tagMapper.selectList(new LambdaQueryWrapper<>())
                .stream()
                .collect(Collectors.toMap(t -> t.getName(), t -> t.getId()));
        return tagMap;
    }

    /**
     *
     * @return 系统语言
     */
    protected Map<String, Language> getLanguageMap() {
        //语言
        Map<String, Language> languageMap = languageMapper.selectList(new LambdaQueryWrapper<>())
                .stream()
                .collect(Collectors.toMap(t -> t.getName(), t -> t));
        return languageMap;
    }

    protected ImportProblemVO parseProblemVO(File file){
        FileReader fileReader = new FileReader(file);
        ImportProblemVO importProblemVo = JSONUtil.toBean(fileReader.readString(), ImportProblemVO.class);
        return importProblemVo;
    }

    protected void setDefaultProblem(Problem problem,Problem defaultProblem){

        if(problem ==null || defaultProblem == null)
            return;

        if(problem.getDifficultyId() == null){
            problem.setDifficultyId(defaultProblem.getDifficultyId());
        }
        if(problem.getProblemTypeId() == null){
            problem.setProblemTypeId(defaultProblem.getProblemTypeId());
        }

        if(StringUtils.isEmpty(problem.getProblemLanguageList())){
            problem.setProblemLanguageList(BeanUtil.copyToList(defaultProblem.getProblemLanguageList(),ProblemLanguage.class));
        }

        if(StringUtils.isEmpty(problem.getTagIds())){
            problem.setTagIds(defaultProblem.getTagIds());
        }

    }

    protected void setCoverProblem(Problem problem,Problem coverProblem){

        if(problem == null || coverProblem == null)
            return;

        if(coverProblem.getDifficultyId() != null){
            problem.setDifficultyId(coverProblem.getDifficultyId());
        }
        if(coverProblem.getProblemTypeId() != null){
            problem.setProblemTypeId(coverProblem.getProblemTypeId());
        }

        if(StringUtils.isNotEmpty(coverProblem.getProblemLanguageList())){
            problem.setProblemLanguageList(BeanUtil.copyToList(coverProblem.getProblemLanguageList(),ProblemLanguage.class));
        }

        if(StringUtils.isNotEmpty(coverProblem.getTagIds())){
            problem.setTagIds(coverProblem.getTagIds());
        }
    }

    /**
     *
     * @param tagMap 系统的标签
     * @param tags 题目的标签
     * @param source 标签来源 默认为SYSTEM
     */
    protected List<Long> createTags(Map<String, Long> tagMap, List<String> tags,String source){
        if(source == null)
            source = "SYSTEM";
            // 格式化标签
        List<Long> ans = new ArrayList<>();
        for (String tagStr : tags) {
            Long tagId = tagMap.getOrDefault(tagStr.toUpperCase(), null);
            if (tagId == null) {
                Tag tag = new Tag()
                        .setName(tagStr)
                        .setSource(source);
                int insert = tagMapper.insert(tag);
                tagMap.put(tagStr,tag.getId());
                if (insert == 0)
                    throw new BizException("标签[" + tagStr + "]生成失败！");

                tagId = tag.getId();
            }
            ans.add(tagId);
        }

        return ans;

    }
}
